package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    /**
     * 保存声音
     * @param trackInfoVo
     * @return
     */
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        //涉及到三张表，将整体的步骤分成三步：
        //1、保存声音，向声音基本信息表  track_info表  添加数据
        //添加声音的基本信息,因为现需要的是TrackInfo类型，但是前端传过来的是TrackInfoVo类型，所以需要进行转换
        TrackInfo trackInfo = new TrackInfo();
        //使用BeanUtils的方法，批量将Vo数据复制到对应的TrackInfo对象中，但是还有些值需要进行处理
        BeanUtils.copyProperties(trackInfoVo, trackInfo);

        //需要手动设置
        //TODO 用户id
        trackInfo.setUserId(1L);

        //修改声音信息表中的order_num字段，表示声音在专辑中的排序值，需要保证一定比当前已有的最大值还要大
        //我们这里，直接给最大值+1即可
        //声音在专辑中的排序值 获取专辑下面最大order_num
        //select order_num from track_info where album_id=1 order by id desc limit 1
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>();
        //设置查询字段 order_num
        wrapper.select(TrackInfo::getOrderNum);
        //专辑id查询
        wrapper.eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId());
        //根据声音id降序，为了获取第一条的声音数量
        wrapper.orderByDesc(TrackInfo::getId);
        //获取第一条记录,.last的含义是：无论前面的语句多少，在语句的最后添加内容
        //因此需要注意，()内的内容需要在前面加一个空格，防止关键字和前面的内容连在一起导致关键字失效
        wrapper.last(" limit 1 ");
        //调用，因为只需要一条，所以selectone()就可以
        TrackInfo trackInfo_ordernum = trackInfoMapper.selectOne(wrapper);

        int orderNum = 1;
        //非空判断，在新增专辑之后，第一次添加声音的时候，里面是没有声音的，ordernum为空，这里就是考虑到这种情况，防止空指针
        if (null != trackInfo_ordernum) {
            orderNum = trackInfo_ordernum.getOrderNum() + 1;
        }
        //最大值+1
        trackInfo.setOrderNum(orderNum);

        //声音其他信息，比如时长，大小，类型等
        //这些信息到腾讯云查询
        //根据声音的mediaFileId(腾讯云服务器的文件ID)调用腾讯云方法获取
        TrackMediaInfoVo trackMediaInfoVo =
                vodService.getmediaInfoByFileId(trackInfoVo.getMediaFileId());
        //设置到trackInfo
        trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        //在将相关的参数都设置完成之后，调用方法添加
        trackInfoMapper.insert(trackInfo);

        //2、操作专辑表，修改专辑里面声音数量值，+1
        //根据专辑id查询专辑原始数据 includeTrackCount字段，代表声音的数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        Integer includeTrackCount = albumInfo.getIncludeTrackCount();
        //把原始数量+1
        albumInfo.setIncludeTrackCount(includeTrackCount + 1);
        //调用方法更新
        albumInfoMapper.updateById(albumInfo);

        //还是提出一个方法，然后执行四次即可
        //3、添加声音四个统计数据，初始值0 track_stat表
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
    }

    /**
     * 查询声音分类列表
     * @param pageParam      Page对象
     * @param trackInfoQuery
     * @return
     */
    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> pageParam, TrackInfoQuery trackInfoQuery) {
        //因为mybatis-plus没有可以使用的方法来实现查询目的，因为涉及到多张表
        return trackInfoMapper.selectUserTrackPage(pageParam, trackInfoQuery);
    }

    /**
     * 删除声音文件
     * @param id 要删除的声音文件的id
     * @return //思路剖析：删除涉及到的表有三张
     */
    @Override
    public void removeTrackInfo(Long trackId) {

        //根据声音id获取专辑信息
        //注意，这个放在删除声音基本信息表之前，因为如果放在之后的话，永远为null,导致空指针，需要注意这种执行顺序
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

        //1、删除声音基本信息表的数据
        trackInfoMapper.deleteById(trackId);

        //2、修改专辑信息表的声音数量，为原有值的基础上-1
        //通过查询到的专辑信息获取专辑Id
        Long albumId = trackInfo.getAlbumId();
        //根据专辑id查询专辑数据，把数量-1，进行更新
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //取出声音数量的值
        Integer includeTrackCount = albumInfo.getIncludeTrackCount();
        //修改为原值-1
        albumInfo.setIncludeTrackCount(includeTrackCount - 1);
        albumInfoMapper.updateById(albumInfo);

        //3、删除声音相关数据表的数据
        LambdaQueryWrapper<TrackStat> wrapper = new LambdaQueryWrapper<>();
        //条件：声音id = 传入的id
        wrapper.eq(TrackStat::getTrackId, trackId);
        trackStatMapper.delete(wrapper);

        //4、删除腾讯云上面对应的文件
        vodService.removeTrack(trackInfo.getMediaFileId());
    }

    /**
     * 修改声音
     * @param trackId     声音ID
     * @param trackInfoVo 请求体中声音的信息
     * @return //思路：修改，先判断声音文件有没有修改，如果修改，我们还需要再去腾讯云去获取其他信息，如果没有修改，直接修改其他内容即可
     */
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        //1、先判断声音文件是否修改，这里的思路是：前端传的id是否和数据库对应trackId的声音FileId相同
        //先根据trackId获取数据库对应trackId的声音FileId
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        String mediaFileId_database = trackInfo.getMediaFileId();

        //获取前端传入的FileId
        //设置修改值
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        String mediaFileId_new = trackInfo.getMediaFileId();
        //对这两个值进行比较，如果不相同，表示声音文件发生修改，需要重新获取相关的参数，包括声音文件的时长，大小，类型等信息
        if (!mediaFileId_new.equals(mediaFileId_database)) {
            //调用腾讯云的方法，重新获取声音文件的时长，文件大小，存储地址，文件类型
            TrackMediaInfoVo trackMediaInfoVo =
                    vodService.getmediaInfoByFileId(trackInfoVo.getMediaFileId());
            //这里对根据id获取的内容进行非空判断，可能存在管理员在腾讯云端将文件删除的极端情况，需要考虑
            if (null == trackMediaInfoVo) {
                throw new GuiguException(ResultCodeEnum.VOD_FILE_ID_ERROR);
            }
            //将这些值分别重新设置
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());

            //删除之前声音文件
            vodService.removeTrack(mediaFileId_database);
        }
        //调用方法修改
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * 查找专辑下面声音信息列表
     * @param pageParam
     * @param albumId
     * @param userId
     * @return
     */
    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageParam, Long albumId, Long userId) {
        //根据专辑id分页查询得到数据,这是获取的所有分类数据，是一个result
        IPage<AlbumTrackListVo> pageInfo =
                trackInfoMapper.findAlbumTrackPage(pageParam, albumId);

        //根据专辑id获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //非空判断
        Assert.notNull(albumInfo, "专辑数据为空");
        //获取支付类型
        String payType = albumInfo.getPayType();

        //1 根据userId判断当前是否登录
        if (null == userId) {
            //1.1 如果没有登录
            // isShowPaidMark=flase免费的  isShowPaidMark=true收费的
            //获取付费类型，如果专辑免费直接观看，如果专辑不是免费的，根据tracks_for_free去掉试听集数，其他的是收费的

            //付费类型: 0101-免费、0102-vip免费、0103-付费
            if (!"0101".equals(payType)) {
                //获取专辑所有声音集合
                List<AlbumTrackListVo> allAlbumTrackList = pageInfo.getRecords();
                //获取专辑试听集数
                Integer tracksForFree = albumInfo.getTracksForFree();
                //从所有声音集合过滤掉试听集数,声音表有order_num排序 order_num>试听集数
                List<AlbumTrackListVo> trackListVoList =
                        allAlbumTrackList.stream().filter(albumTrackListVo ->
                                        albumTrackListVo.getOrderNum().intValue() > tracksForFree)
                                .collect(Collectors.toList());
                //trackListVoList集合每个对象中 isShowPaidMark = true
                if (!CollectionUtils.isEmpty(trackListVoList)) {
                    trackListVoList.forEach(albumTrackListVo -> {
                        // 显示付费通知
                        // isShowPaidMark=flase免费的  isShowPaidMark=true收费的
                        albumTrackListVo.setIsShowPaidMark(true);
                    });
                }
            }

        } else {
            //1.2 如果登录状态
            //判断如果专辑vip免费的
            //* 如果用户没有开通vip，     收费
            //* 如果用户开通VIP但是过期了，收费
            boolean isNeedPaid = false;
            //付费类型: 0101-免费、0102-vip免费、0103-付费
            if ("0102".equals(payType)) {
                // 根据当前登录的用户id获取用户信息，判断用户是否开通vip
                // 如果用户没有开通vip，     收费
                Result<UserInfoVo> userInfoVoResult =
                        userInfoFeignClient.getUserInfoVo(userId);
                //获取用户信息
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                //非空判断
                Assert.notNull(userInfoVo, "用户信息为空");
                //获取vip字段
                Integer isVip = userInfoVo.getIsVip();
                //如果没有开通vip
                if (isVip.intValue() == 0) {
                    isNeedPaid = true;
                }

                //* 如果用户开通VIP但是过期了，收费
                Date vipExpireTime = userInfoVo.getVipExpireTime();
                if (isVip.intValue() == 1 && vipExpireTime.before(new Date())) {
                    isNeedPaid = true;
                }
            } else if ("0103".equals(payType)) { //0103-付费
                isNeedPaid = true;
            }
            //考虑登录之后，如果付费
            if(isNeedPaid) {
                //下面几种情况
                // 判断当前用户是否购买专辑，购买过，免费
                // 如果用户购买整个专辑，专辑里面所有声音免费
                // 如果用户只是购买了专辑某些声音，购买的声音免费的，其他收费
                //获取排除试听声音列表
                List<AlbumTrackListVo> albumTrackNeedPaidListVoList =
                        pageInfo.getRecords().stream()
                                .filter(albumTrackListVo ->
                                        albumTrackListVo.getOrderNum().intValue() > albumInfo.getTracksForFree())
                                .collect(Collectors.toList());

                if(!CollectionUtils.isEmpty(albumTrackNeedPaidListVoList)) {
                    //albumTrackNeedPaidListVoList获取所有声音id
                    List<Long> trackIdList =
                            albumTrackNeedPaidListVoList.stream()
                                    .map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());

                    //远程调用接口，查询用户购买过的专辑或者声音
                    //[1,2,3,4]
                    Result<Map<Long, Integer>> mapResult =
                            userInfoFeignClient
                                       .userIsPaidTrack(albumId,trackIdList);
                    //map的key是声音id  value：1购买过  0没有购买过
                    Map<Long, Integer> map = mapResult.getData();
                    //非空判断
                    Assert.notNull(map,"为空");
                    //albumTrackNeedPaidListVoList集合，声音id比较，1：isShowPaidMark = false
                    albumTrackNeedPaidListVoList.forEach(albumTrackListVo -> {
                        Long trackId = albumTrackListVo.getTrackId();

                        //根据声音ID获取value，这个值是1，就是false，表示对当前用户，显示免费标识
                        boolean isMark = map.get(trackId)==1?false:true;
                        albumTrackListVo.setIsShowPaidMark(isMark);
                    });
                }
            }

        }
        return pageInfo;
    }

    /**
     * 更新数据
     * @param trackStatMqVo
     */
    @Override
    public void updateStat(TrackStatMqVo trackStatMqVo) {
        //声音ID
        Long trackId = trackStatMqVo.getTrackId();
        //更新数目
        Integer count = trackStatMqVo.getCount();
        //统计类型
        String statType = trackStatMqVo.getStatType();

        //根据声音id+ 0701获取数据
        LambdaQueryWrapper<TrackStat> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackStat::getTrackId, trackId);
        wrapper.eq(TrackStat::getStatType, statType);
        TrackStat trackStat = trackStatMapper.selectOne(wrapper);

        //设置修改值
        trackStat.setStatNum(trackStat.getStatNum()+count);

        //调用方法更新
        trackStatMapper.updateById(trackStat);
    }


    /**
     * 初始化统计数量
     * @param trackId   修改的表的id
     * @param trackType 要修改成什么值
     */
    private void saveTrackStat(Long trackId, String trackType) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(trackType);
        trackStat.setStatNum(0);
        this.trackStatMapper.insert(trackStat);
    }
}
